﻿/* 关于 IB, 您可以参考 http://blog.sina.com.cn/s/blog_604c436d0100o5j0.html.
 * IB 是项目 zsharedcode 的一部分, 您可以参考 http://code.google.com/p/zsharedcode/ 或者 http://blog.sina.com.cn/s/blog_604c436d0100o04s.html.
 * Visual Studio 2010 项目模板请访问 http://blog.sina.com.cn/s/blog_604c436d0100o8gn.html.
 * 所有项目源码托管地址: http://panzer.codeplex.com/.
 * */
using System;
using System.Windows.Forms;

using zoyobar.shared.panzer;
using zoyobar.shared.panzer.web;
using zoyobar.shared.panzer.web.ib;

namespace IBBloggerTemplate
{

	internal class SinaBlog
		: Blog
	{
		// 载入 blog 首页的状态名称。
		private const string loadHomePageStateName = "load home page";
		// blog 首页安装 jquery 的状态名称。
		private const string homePageInstallJQueryStateName = "home page install jquery";

		// 首页测试是否登录的状态名称。
		private const string testIsLoginStateName = "test is login";
		// 首页显示登录框的状态名称。
		private const string loginUIStateName = "login ui";
		// 首页登录的状态名称。
		private const string loginStateName = "login";
		// 首页登录成功后的状态名称。
		private const string loginedStateName = "logined";
		// 载入日志编辑页面的状态名称。
		private const string editBlogStateName = "edit blog";
		// 日志编辑页面安装 jquery 的状态名称。
		private const string editBlogPageInstallJQueryStateName = "edit blog page install jquery";
		// 发布日志的状态名称。
		private const string publicBlogStateName = "public blog";
		// TODO: 可以在此处添加新的或者修改上面的页面状态名称。

		// 载入 blog 首页的状态。
		private readonly WebPageState loadHomePageState;
		// blog 首页安装 jquery 的状态。
		private readonly WebPageState homePageInstallJQueryState;

		// 首页测试是否登录的状态。
		private readonly WebPageState testIsLoginState;
		// 首页显示登录框的状态。
		private readonly WebPageState loginUIState;
		// 首页登录的状态。
		private readonly WebPageState loginState;
		// 判断是否登录成功的状态。
		private readonly WebPageState loginedState;

		// 载入日志编辑页面的状态。
		private readonly WebPageState editBlogState;
		// 日志编辑页面安装 jquery 的状态。
		private readonly WebPageState editBlogPageInstallJQueryState;
		// 发布日志的状态。
		private readonly WebPageState publicBlogState;
		// TODO: 可以在此处添加新的或者修改上面的页面状态。

		// 获取编辑页面上标题标签的 jquery 。
		private readonly string titleTagJQuery;
		// 获取编辑页面上文本框标签的 jquery 。
		private readonly string textTagJQuery;
		// 获取编辑页面上分类标签的 jquery 。
		private readonly string catalogTagJS;
		// 获取编辑页面上文章标签的标签的 jquery 。
		private readonly string tagTagJQuery;
		// 获取编辑页面切换源代码标签的 jquery 。
		private readonly string shiftEditModeTagJQuery;

		// 使用已有的设置创建 SinaBlog 。
		internal SinaBlog ( WebBrowser browser, string homePage, string userName, string password )
			: this ( browser, homePage, userName, Program.Settings["SinaUserNameTagJQuery"], password, Program.Settings["SinaPasswordTagJQuery"], Program.Settings["SinaTestIsLoginTagJQuery"], Program.Settings["SinaTestIsLoginTagJS"], Program.Settings["SinaLoginTagJS"], Program.Settings["SinaEditBlogPage"], Program.Settings["SinaTitleTagJQuery"], Program.Settings["SinaTextTagJQuery"], Program.Settings["SinaCatalogTagJS"], Program.Settings["SinaTagTagJQuery"], Program.Settings["SinaPublicTagJS"], Program.Settings["SinaShiftEditModeTagJQuery"] )
		{ }
		internal SinaBlog ( WebBrowser browser, string homePage, string userName, string userNameTagJQuery, string password, string passwordTagJQuery, string testIsLoginTagJQuery, string testIsLoginTagJS, string loginTagJS, string editBlogPage, string titleTagJQuery, string textTagJQuery, string catalogTagJS, string tagTagJQuery, string publicTagJS, string shiftEditModeTagJQuery )
			: base ( browser, homePage, userName, userNameTagJQuery, password, passwordTagJQuery )
		{

			if ( string.IsNullOrEmpty ( testIsLoginTagJQuery ) || string.IsNullOrEmpty ( testIsLoginTagJS ) || string.IsNullOrEmpty ( loginTagJS ) || string.IsNullOrEmpty ( editBlogPage ) || string.IsNullOrEmpty ( titleTagJQuery ) || string.IsNullOrEmpty ( textTagJQuery ) || string.IsNullOrEmpty ( catalogTagJS ) || string.IsNullOrEmpty ( tagTagJQuery ) || string.IsNullOrEmpty ( publicTagJS ) || string.IsNullOrEmpty ( shiftEditModeTagJQuery ) )
				throw new ArgumentNullException ( );

			this.titleTagJQuery = titleTagJQuery;
			this.textTagJQuery = textTagJQuery;
			this.catalogTagJS = catalogTagJS;
			this.tagTagJQuery = tagTagJQuery;
			this.shiftEditModeTagJQuery = shiftEditModeTagJQuery;

			// 载入 blog 首页的状态。
			this.loadHomePageState = new WebPageState (
				loadHomePageStateName,
				new NavigateAction ( homePage, 5 ), // 这里跳转到 blog 首页，并等待 5 秒钟。
				new WebPageNextStateSetting ( // 这里表示，当载入 blog 首页后，自动转到安装 jQuery 的状态。
					homePageInstallJQueryStateName,
					true
				),
				new UrlCondition ( homePage, homePage, StringCompareMode.StartWith ) // 这里表示当 blog 页面载入后，表示状态完成。
				);

			// blog 首页安装 jquery 的状态。
			this.homePageInstallJQueryState = new WebPageState (
				homePageInstallJQueryStateName,
				//	TODO: 在此处修改为自定义的 jQuery 脚本下载地址。之前使用载入本地的 jquery 脚本由于编码问题出现错误，现使用另外的方式加载。
				new WebPageAction[] {
					new InstallTraceAction ( ), // 这里安装跟踪脚本，是 jQuery 所需的脚本。
					new InstallJavaScriptAction ( Properties.Resources.jquery_1_5_min, "jsJQuery_1_5" ) // 这里安装 jQuery 1.5 。
				},
				new WebPageNextStateSetting ( // 这里表示，当载入 jQuery 后，自动转到判断是否登录的状态。
					testIsLoginStateName,
					true
				)
				);

			// 首页测试是否登录的状态。
			this.testIsLoginState = new WebPageState (
				testIsLoginStateName,
				new WebPageNextStateSetting ( // 这里表示，如果已经登录直接跳转到编辑日志的页面状态。
					editBlogStateName,
					true
				),
				new WebPageNextStateSetting ( // 这里表示，如果没有登录跳转到准备登录的页面状态。
					loginUIStateName,
					true
				),
				new JQueryCondition ( "jquery test", JQuery.Create ( testIsLoginTagJQuery ).Length ( ), "0" ), // 这里表示，如果指定的标签存在，那么认为没有登录。
				2 // 如果 2 秒后，仍然检测为没有登录，则认为登录状态失败，准备登录。
				);

			// 首页显示登录框的状态。
			this.loginUIState = new WebPageState (
				loginUIStateName,
				new ExecuteJavaScriptAction ( string.Format ( "{0}.click();", testIsLoginTagJS ) ), // 这里表示点击登录按钮，显示登录界面，也可以使用 JQuery 类的 Trigger 方法，但不适用于 a 标签。
				new WebPageNextStateSetting ( // 这里表示，如果登录界面已经显示则跳转到填写信息并登录的页面状态。
					loginStateName,
					true
				),
				new JQueryCondition ( "jquery user name", JQuery.Create ( userNameTagJQuery ).Length ( ), 1 ) // 这里表示，如果用户名标签存在，则认为登录界面已经显示。
				);

			// 首页登录的状态。
			this.loginState = new WebPageState (
				loginStateName,
				new WebPageAction[] {
					new ExecuteJQueryAction ( JQuery.Create ( userNameTagJQuery ).Val ( string.Format ( "'{0}'", IEBrowser.EscapeCharacter ( userName ) ) ) ), // 这里表示填写用户名。
					new ExecuteJQueryAction ( JQuery.Create ( passwordTagJQuery ).Val ( string.Format ( "'{0}'", IEBrowser.EscapeCharacter ( password ) ) ) ), // 这里表示填写密码。
					new ExecuteJavaScriptAction ( string.Format ( "{0}.click();", loginTagJS ) ) // 这里表示点击登录按钮，也可以使用 JQuery 类的 Trigger 方法，但不适用于 a 标签。
				},
				new WebPageNextStateSetting ( // 这里表示，点击登录后进入判断是否登录成功的状态。
					loginedStateName,
					true
				)
				);

			// 判断是否登录成功的状态。
			this.loginedState = new WebPageState (
				loginedStateName,
				new WebPageNextStateSetting ( // 这里表示，如果登录成功则进入载入编辑页面的状态。
					editBlogStateName,
					true
				),
				new ExecuteJavaScriptAction ( "alert('登录失败, 用户名或者密码错误!');" ), // 如果登录不成功，则弹出对话框。
				new UrlCondition ( homePage, homePage, StringCompareMode.StartWith ), // 如果页面重新载入一次，则认为登录成功。
				// TODO: 如果网速过慢，可以延长超时时间。
				10 // 如果 10 秒钟页面还没有重新载入，则认为登录失败。
				);

			// 载入日志编辑页面的状态。
			this.editBlogState = new WebPageState (
				editBlogStateName,
				new NavigateAction ( editBlogPage, 5 ), // 载入日志编辑页面，并等待 5 秒钟。
				new WebPageNextStateSetting ( // 这里表示，载入成功后，进入安装 jQuery 的状态。
					editBlogPageInstallJQueryStateName,
					true
				),
				new UrlCondition ( editBlogPage, editBlogPage, StringCompareMode.StartWith ) // 但编辑页面载入时，认为状态完成。
				);

			// 日志编辑页面安装 jquery 的状态。
			this.editBlogPageInstallJQueryState = new WebPageState (
				editBlogPageInstallJQueryStateName,
				//	TODO: 在此处修改为自定义的 jQuery 脚本下载地址。之前使用载入本地的 jquery 脚本由于编码问题出现错误，现使用另外的方式加载。
				new WebPageAction[] {
					new InstallTraceAction ( ), // 这里安装跟踪脚本，是 jQuery 所需的脚本。
					new InstallJavaScriptAction ( Properties.Resources.jquery_1_5_min, "jsJQuery_1_5" ) // 这里安装 jQuery 1.5 。
				},
				new WebPageNextStateSetting ( // 安装 jQuery 后，进入日志的发布状态。
					publicBlogStateName,
					true
				)
				);

			// 发布日志的状态。
			this.publicBlogState = new WebPageState (
				publicBlogStateName,
				new WebPageAction[] {
					new EmptyAction ( ), // 这里是填写标题，由于标题需要用户输入，这里此命令设置为空命令。
					new EmptyAction ( ), // 这里是是否切换显示源代码，同上也是空命令。
					new EmptyAction ( ), // 这里是填写内容，由于内容需要用户输入，这里此命令设置为空命令。
					new EmptyAction ( ), // 这里是填写分类，由于分类需要用户输入，这里此命令设置为空命令。
					new EmptyAction ( ),  // 这里是填写标签，由于标签需要用户输入，这里此命令设置为空命令。
					new ExecuteJavaScriptAction ( string.Format ( "{0}.click();", publicTagJS ) )
				}
				);

			// 创建核心 IEBrowser。
			this.ie = new IEBrowser ( browser, new WebPageState[] { this.loadHomePageState, this.homePageInstallJQueryState, this.testIsLoginState, this.loginUIState, this.loginState, this.loginedState, this.editBlogState, this.editBlogPageInstallJQueryState, this.publicBlogState } );
		}

		internal override void WriteBlog ( string title, string textHTML, string catalog, string tag, bool isShiftEditMode )
		{
			// 点击发布按钮后，设置发布日志状态的各个命令。
			this.publicBlogState.StartActions[0] = new ExecuteJQueryAction ( JQuery.Create ( this.titleTagJQuery ).Val ( string.Format ( "'{0}'", IEBrowser.EscapeCharacter ( title ) ) ) ); // 设置填写标题的命令。

			// 设置是否切换显示源代码的命令。
			if ( isShiftEditMode )
				this.publicBlogState.StartActions[1] = new ExecuteJQueryAction ( JQuery.Create ( this.shiftEditModeTagJQuery ).Trigger ( "'click'" ) );
			else
				this.publicBlogState.StartActions[1] = new EmptyAction ( );

			this.publicBlogState.StartActions[2] = new ExecuteJQueryAction ( JQuery.Create ( this.textTagJQuery ).Val ( string.Format ( "'{0}'", IEBrowser.EscapeCharacter ( textHTML ) ) ) ); // 设置填写内容的命令。
			this.publicBlogState.StartActions[3] = new ExecuteJavaScriptAction ( string.Format ( this.catalogTagJS, IEBrowser.EscapeCharacter ( catalog ) ) ); // 设置填写分类的命令。
			this.publicBlogState.StartActions[4] = new ExecuteJQueryAction ( JQuery.Create ( this.tagTagJQuery ).Val ( string.Format ( "'{0}'", IEBrowser.EscapeCharacter ( tag ) ) ) ); // 设置填写标签的命令。

			// 从载入首页的状态开始。
			this.ie.IEFlow.JumpToState ( loadHomePageStateName );
		}

	}

}
